# _*_coding:utf-8_*_
import os
import socket
import socketserver
import threading
import time
import SocketServer_constant
import re

from ATS import linearize4SemiCon
from ATS.eeManager import EEManager
from ATS.errHandler import errHandler
from ATS.globaldata import gdata
from ATS.datamanager import DbImpl
from ATS.datamanager import DbServer
from ATS.datamanager import DmConstant
from utils.log_util import loggings as logger
import traceback
from ATS.linearize4SemiCon import ppf as ppfModule
from ATS.util import constant


class MyServer(socketserver.BaseRequestHandler):
    def handle(self):
        self.request.sendall(bytes("Client Success", encoding="utf-8"))
        ind = 0
        send_rtd_afterStop = False
        try:
            global eem_obj
            eem_obj = EEManager.get_EEM()
        except Exception as e:
            self.request.sendall(bytes(str(e), encoding="utf-8"))
        else:
            self.request.sendall(bytes("Velox Success", encoding="utf-8"))
        while True:
            try:
                recv_data = self.request.recv(SocketServer_constant.MAX_MSG_LEN)
                if recv_data == 0:
                    break
                msg = recv_data.decode("utf-8")
                if msg and msg.strip() != '':
                    logger.debug('Get msg from socket: <' + msg + '>')
                    if msg == SocketServer_constant.CLIENT_CLOSE:
                        break
            except ConnectionResetError as msg1:
                break
            except Exception as e:
                time.sleep(0.2)
                if constant.CUSTOMIZE_FOR_LOOP:
                    ind += 1
                    if eem_obj.get_running_flag():
                        send_rtd_afterStop = True
                        if ind % 10 == 0:
                            self.request.send((
                                                      'realtime data===%s#' % str(
                                                  gdata.getGDD()['real_time_data'])).encode("utf-8"))
                else:
                    if send_rtd_afterStop:
                        send_rtd_afterStop = False
                    time.sleep(2.5)
                    self.request.send(('realtime data===%s#' % str(gdata.getGDD()['real_time_data'])).encode("utf-8"))
                continue
            else:
                #            self.parse_msg(msg)
                commands = msg.split('#')
                print("commands", commands)
                for msg in commands:
                    if not msg:
                        continue
                    msg += '#'
                    print('#####parse msg:', msg)
                    kwargs = {'msg': msg}
                    parseThread = threading.Thread(None, self.parse_msg, "ParseMsg", (), kwargs)
                    parseThread.start()

        # 解析数据

    def parse_msg(self, msg):
        if msg and msg.strip() != '':
            logger.debug('SocketServer get msg: <' + msg + '>')
        if re.match(SocketServer_constant.RUN_PPF_CMD, msg, re.IGNORECASE):
            m = re.findall(SocketServer_constant.RUN_PPF_CMD, msg)
            if not m[0]:
                run, ppf = msg.split('-')
                logger.debug('Enter run_ppf with no append run')
                self.run_ppf(ppf[:-1])
            else:  # with parameter -a , append run test
                run, ppf, param = msg.split('-')
                print('######append run ppf:', ppf[:-1])
                logger.debug('Enter run_ppf with append run')
                self.run_ppf(ppf, append=True)
        elif re.match(SocketServer_constant.STOP_CMD, msg, re.IGNORECASE):
            logger.debug('Enter on_stop')
            self.on_stop()
        # elif re.match(SocketServer_constant.STOP_SIP_TOOLS_CMD,msg,re.IGNORECASE):
        #     self.on_stop_sip()
        elif re.match(SocketServer_constant.PAUSE_CMD, msg, re.IGNORECASE):
            self.on_pause(True)
        elif re.match(SocketServer_constant.RESUME_CMD, msg, re.IGNORECASE):
            self.on_pause(False)
        elif re.match(SocketServer_constant.UPDATE_GDATA_CMD, msg, re.IGNORECASE):
            # update global data can be synchonized in parse_msg function
            # because it cost even no time
            msg_content = msg.replace('update-', '')
            msg_content = msg_content[:-1]
            vars = msg_content.split(',')
            update_dict = {}
            for var in vars:
                tmp = var.split('=')
                n = tmp[0]
                v = tmp[1]
                try:
                    update_dict[n] = eval(v)
                except:
                    update_dict[n] = v
            gdata.updateGDD(update_dict)
        elif re.match(SocketServer_constant.UPDATE_REALTIMEGDATA_CMD, msg, re.IGNORECASE):
            # update real time global data can be synchonized in parse_msg function
            # because it cost even no time
            msg_content = msg.replace('update_realtimedata-', '')
            msg_content = msg_content[:-1]  # remove #
            vars = msg_content.split(',')
            update_dict = {}
            for var in vars:
                tmp = var.split('=')
                n = tmp[0]
                v = tmp[1]
                try:
                    update_dict[n] = eval(v)
                except:
                    update_dict[n] = v
            gdata.updateRealTimeGDD(update_dict)

    def on_pause(self, flag):
        eem_obj.set_pause(flag)
        DbServer.Commit_db()

    def on_stop(self):
        eem_obj.on_stop()
        DbServer.Commit_db()
        DbServer.stop()

    # def on_stop_sip(self):
    #     eem_obj.on_stop()

    # 创建数据库
    def register_curr_db(self, ppf, lot_num="", time_v=""):
        cur_db_di = {}
        print(ppf)
        result = os.path.splitext(ppf)[0]
        base_d = os.path.join(constant.DB_PATH, result)
        if not os.path.exists(base_d):
            os.makedirs(base_d)
        curr_db = os.path.join(base_d, "%s.db" % result)
        cur_db_di[constant.CURR_DB_FILE] = curr_db
        gdata.register_service(cur_db_di)
        return curr_db

    def run_ppf(self, ppf, append=False):
        """this function is run the ppf file,the ppf parameter format like '0402.ppf@1231__1231__121__1' """
        data_model = None
        try:
            batch_num = ""
            group_num = ""
            product_num = ""
            tech_pha = ""
            if ppf.count('@') > 0:  # there is a "@" symbol in the ppf parameter
                ppf, misc_info = ppf.split('@')
                misc_list = misc_info.split(SocketServer_constant.SPLITER)
                if len(misc_list) == 4:
                    batch_num = misc_list[0]
                    group_num = misc_list[1]
                    product_num = misc_list[2]
                    tech_pha = misc_list[3]

            curr_db_file = self.register_curr_db(ppf, batch_num, group_num)
            # write batch num and group num to the database
            data_model = DbImpl.fetch_data_model()
            model_value = {constant.DATA_MODEL_INSTANCE: data_model}
            gdata.register_service(model_value)
            try:
                #                flag,data_con = DbImpl.fetch_data_con_by(ppf)
                print(DbImpl.fetch_data_con_by_file(curr_db_file))
                flag, data_con = DbImpl.fetch_data_con_by_file(curr_db_file)
            except:
                logger.error(f"Error while fetching data connection instance:{traceback.format_exc()}")
            else:
                data_model.set_connection(data_con)

            ppf_dict = {constant.CURR_PPF_KEY: ppf}
            gdata.register_service(ppf_dict)  # add the ppf_dict to the globaldata

            if ppf.endswith(constant.INKING_PPF_POSTFIX):
                index = ppf.find(constant.INKING_PPF_POSTFIX)
                inking_value = {constant.INK_ORI_PPF: ppf[0:index] + ".ppf"}
                gdata.register_service(inking_value)
            data_model.build_base_tables(keep_existing=True)
            prj = os.path.splitext(ppf)[0]
            print("prj is:", prj)
            data_model.on_project_run(prj, is_append=append, batch_num=batch_num, group_num=group_num,
                                      prod_num=product_num, tech_phase=tech_pha)
            logger.debug("before regist misc")
            data_model.register_misc_item(DmConstant.ITEM_IN_RUNNING, DmConstant.VALUE_TRUE)
            logger.debug("After regist misc")
            err = linearize4SemiCon.linearizeTestPlan.linearize_ppf(ppf)
            #            linearize4SemiCon.linearizeTestPlan.output_MTL()
            if err != linearize4SemiCon.linearizeTestPlan.NO_ERR:
                errHandler.handle_err('LinerizeTestPlan', err, "Parse input test plan files error!",
                                      level="fail")
                time.sleep(1)
                logger.debug("Send complete from server! ")
                DbServer.Commit_db()
                self.request.send(SocketServer_constant.COMPLETE_CMD.encode("utf-8"))
            else:
                if data_model:
                    sspf_o = ppfModule.get_sspf_obj(os.path.join(constant.PPF_PATH, ppf))
                    if constant.NEED_REGISTER_LOCATION or sspf_o.repeat is None or len(sspf_o.repeat) == 0:
                        index_loc_map = data_model.register_globation_location(gdata.getLMD())
                        gdata.updateGDD(index_loc_map)
                else:
                    print("No data model instance in gdata container.")
                print("program run to the eemanager.get_EEM()")
                err = eem_obj.run_MTL()
                if err != EEManager.NO_ERR:
                    logger.debug("Find error: " + str(err))
                DbServer.Commit_db()
                logger.debug("Send complete from server! ")
                self.request.send(SocketServer_constant.COMPLETE_CMD.encode("utf-8"))
                DbServer.stop()
            data_model.register_misc_item(DmConstant.ITEM_IN_RUNNING, DmConstant.VALUE_FALSE)
            data_model.release_con()
        except:
            logger.error("Error in running ppf %s: %s" % (ppf, traceback.format_exc()))
            DbServer.Commit_db()
            DbServer.stop()
            if data_model:
                data_model.release_con()

            logger.debug("Send complete from server! ")
            self.request.send(SocketServer_constant.COMPLETE_CMD.encode("utf-8"))


class SocketServer:
    """
        Socket server, only support one client.
    """

    def __init__(self):
        self.host = socket.gethostbyname(socket.gethostname())
        # server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server = socketserver.ThreadingTCPServer((self.host, SocketServer_constant.LIST_PORT), MyServer)
        server.serve_forever()
